// import api_text2img from '@/data/comfyuiapi/workflow_api_text2img.json'
// import api_img2img from '@/data/comfyuiapi/workflow_api_img2img.json'
// import api_faceswap from '@/data/comfyuiapi/workflow_api_faceswap.json'
// import api_img2tagger from '@/data/comfyuiapi/workflow_api_img2tagger.json'
// import api_segment from '@/data/comfyuiapi/workflow_api_segment.json'
// import api_model from '@/data/comfyuiapi/workflow_api_model.json'
// import api_img2video from '@/data/comfyuiapi/workflow_api_img2video.json'
import workflowParams from '@/data/comfyuiapi/workflowParams.json'


import {useTokenUtilgenerateRandomNumber} from "~/utils/tokenUtils";
import axios from 'axios';
import {Buffer} from 'buffer'
import {ImageUrlToBlob, useFileuploadFileToQiniuOSS} from "~/utils/FileUtils";
import {useAuthupdateUserInfo} from "~/composables/authhooks";
import Workflows from "~/pages/admin/workflows.vue";

export interface Param {
    title: string,   //显示名称，参数显示的名称
    name: keyof ComfyUIProperties,   //节点对应的参数名称
    type: string[],  //["节点编号|节点名称“，”属性信息“
    node?: string  //节点
    nodeClass?:string  //节点英文名称
    nodeKey?: string  //节点key
    // nodeTitle?:string //节点中文名称
    param?: string | number  //默认参数
    timeout?: number   //时间秒
    outputType?: 'image' | 'text' | 'video',
    attributes?:any[]
}

// export type ApiType = 'img2img' | 'text2img' | 'faceswap' | 'img2tagger' | 'segment' | 'aimodel' | 'img2video'

//用在外部接口的匹配
export interface ComfyUIProperties {
    ckpt_name?: string
    positive?: string
    negative?: string
    width?: number
    height?: number
    seed?: number
    image_path_origin?: string    //整个工作流只有一张图片输入，一般使用这个参数
    image_path_mask?: string   //遮罩图片
    image_path_face?: string   //换脸场景，脸部参考图片
    image_path_style?: string   //参考图场景，例如ipdapter
    denoise?: number
    segmentpart?: string   //id
    output?: string
    //视频参数
    video_frames?: number,
    fps?: number,
    motion_bucket_id?: number,
    augmentation_level?: number,
    filename_prefix?: string,
    cfg?: number,
    steps?: number,
    min_cfg?: number

    upscale_by?: number //放大倍数
    // SD3专属参数
    sd3_aspect_ratio?: SD3AspectRatio

    custom_dropselect_1?: string  //自定义下拉列表
    custom_dropselect_2?: string

    //在线遮罩编辑
    advance_onlineEdit_origin?:string    //在线遮罩编辑，原图（图像图层部分）
    advance_onlineEdit_mask?:string  //在线遮罩编辑，遮罩部分

    //     自定义参数
    custom_number_1?: number
    custom_string_1?: string
    custom_number_2?: number
    custom_string_2?: string
    custom_number_3?: number
    custom_string_3?: string
    custom_number_4?: number
    custom_string_4?: string
    custom_number_5?: number
    custom_string_5?: string
    custom_number_6?: number
    custom_string_6?: string

}

export class ComfyUI {
    private static Object_info = null as any;
    public static ckpt_names = [] as string[];
    private static useLocal = true
    private static localHttpUrl = ''
    public static preAssignedServer:ServerStatus | null
    private static localWSUrl = ''
    private static websocket: WebSocket;
    private static sd3_key = ''
    private static useOss = false
    private static useCustomizeOss = false
    private static saveHistory = true //是否保存绘画历史记录

    constructor() {
        // ComfyUI.comfyuiAxios.interceptors.response.use(
        //     (response) => {
        //         return response;
        //     },
        //     async (error) => {
        //         const originalRequest = error.config;
        //         if (error?.response?.status === 401 && !originalRequest._retry) {
        //             setTimeout(() => {
        //                 originalRequest._retry = true;
        //             }, 2000);
        //         }
        //         useSnackbarStore().showErrorMessage(error)
        //         return Promise.reject(error);
        //     },
        // );
    }

    /**
     * 重置ComfyUI
     */
    static reSet() {
        this.Object_info = null
        this.ckpt_names = []
    }

    static Initalize = async () => {
        const {
            useLocalComfyUI,
            localComfyUIUrl,
            sd3_key,
            useOss,
            useCustomizeOss,
            ossConfig
        } = useStableDiffusionStore()
        console.log('初始化ComfyUI', localComfyUIUrl)
        this.useLocal = useLocalComfyUI
        this.localHttpUrl = localComfyUIUrl.trim().replace(/\/$/, '')
        this.localWSUrl = localComfyUIUrl.trim().replace(/\/$/, '').replace('http', "ws")
        this.sd3_key = sd3_key
        this.useOss = useOss   //启用OSS
        this.useCustomizeOss = useCustomizeOss
        if (this.useLocal) {
            //赋值给local地址
            //获取本地大模型清单
            if (!this.Object_info) {
                this.Object_info = await this.GET('/object_info')
                if (this.Object_info) {
                    this.ckpt_names = this.Object_info['CheckpointLoaderSimple'].input.required.ckpt_name[0]
                    // console.log("@ComfyUI 初始化获取ComfyUI的节点信息", this.ckpt_names)
                    // 屏蔽SVD模型
                    this.ckpt_names = this.ckpt_names.filter(
                        item => item.indexOf('svd-fp16') === -1,
                    );
                }
            }
            const {user} = useAuthStore()
            //连接本地的服务器
            this.websocket = new WebSocket(`${this.localWSUrl}/ws?clientId=${user?._id}`)
            this.websocket.onopen = (event) => {
                console.log('websocket连接本地Comfy成功', this.localHttpUrl, event)
            }

        } else {
            //连接后端服务器
            if (this.ckpt_names.length === 0) {
                //初始化获取ComfyUI的节点信息
                this.ckpt_names = await this.GET('/draw/getModelList')
                //屏蔽SVD模型
                this.ckpt_names = this.ckpt_names.filter(
                    item => item.indexOf('svd-fp16') === -1 && item.indexOf('sd3_medium') === -1,
                );
                // console.log('链接服务器获取的模型列表',this.ckpt_names)
            }
        }
    };

    /**
     * 工作流数据初始化
     *
     */
    public static async workFlow_Init(workflows: WorkFlow[]) {
        //将初始化获取到的工作流数据传到数据中
        const {user} = useAuthStore()
        const data = await Client_POST(`/workflow`, {
            user_id: user?._id,
            workflows
        })
        console.log('初始化工作流数据', data)
        return data
    }

    /**
     * 获取自己的工作数据
     */
    public static async workFlow_Get() {
        const {user} = useAuthStore()
        const data = await Client_GET(`/workflow/getByUserId/${user?._id}`)
        console.log("从数据库获取到工作流数据", data)
        return data
    }

    /**
     * 获取系统默认的工作流数据,admin账号下
     *
     */
    public static async workFlow_GetDefault(workflowname: string): Promise<WorkFlow> {
        const workflow = await Client_GET(`/workflow/getDefaultWorkflowByName/${workflowname}`) as WorkFlow
        console.log('获取到系统admin默认的工作流', workflowname, workflow)
        return workflow
    }

    /**
     * 保存工作流，可以保存单个工作流，也可以保存工作流数组，同名会进行更新
     */
    public static async workFlow_Save(workflows: WorkFlow[]): Promise<UserWorkFlow> {
        const {user} = useAuthStore()
        const data = await Client_POST(`/workflow/saveWorkflows`, {
            user_id: user?._id,
            workflows
        })
        console.log("更新工作流数据", data)
        return data as UserWorkFlow
    }

    /**
     * 删除工作流，可以删除单个，也可以删除多个，以name查找
     */
    public static async workFlow_Delete(workflows: WorkFlow[]) {
        const {user} = useAuthStore()
        const data = await Client_POST(`/workflow/deleteWorkflows`, {
            user_id: user?._id,
            workflows
        })
        console.log("删除工作流之后的数据", data)
        return data
    }

    /**
     * 从工作流中获取节点,转换为可供选择的节点格式
     */
    public static workFlow_getNodeOptions(workFlow: any) {
        const _nodes = [] as any[]
        const _inputs = [] as any[]
        for (const node in workFlow) {
            // console.log(node)
            //迭代node的inputs节点
            const _child = [] as any[]
            for (const _input in workFlow[node]['inputs']) {
                //如果参数是数组，说明使用其他节点参数，不加入到节点中
                if (typeof workFlow[node]['inputs'][_input] != 'object') {
                    _child.push({
                        label: _input,
                        value: _input,
                        default: workFlow[node]['inputs'][_input]
                    })
                }
                // console.log("typeof workFlow[node]['inputs'][_input]",typeof workFlow[node]['inputs'][_input])
            }
            _nodes.push({
                node: node,
                label: `[${node}]${workFlow[node]['_meta']['title']}`,
                value: `${node}|${workFlow[node]['class_type']}`,
                children: _child
            })
        }
        console.log(`获取的到节点选择`,_nodes)
        return _nodes
    }

    /**
     * 根据节点英文名称class_type获取节点
     * @param workFlow
     * @param name
     */
    static workFlow_getNodeByName(workFlow: any, name: string) {
        for(const node in workFlow){
            if (workFlow[node]['class_type']===name){
                return workFlow[node]
            }
        }
    }

    static workFlow_getNodeList(workFlow: any) {
        // const KSamplers = ["KSampler (Efficient)"]
        //查找所有KSampler节点，并添加参数
        const params = []
        for (const node in workFlow) {
            //读取class_type，_meta.title,inputs下面得所有参数
            for (const paramKey in workFlow[node]['inputs']) {
                if (typeof workFlow[node]['inputs'][paramKey] === "object") {
                    console.log('仍然有下级属性')
                    const nextNode=workFlow[node]['inputs'][paramKey][0]

                } else {
                    const _temp = {
                        node:node,
                        type:[`${node}|${workFlow[node]['class_type']}`,paramKey],
                        nodeClass: workFlow[node]['class_type'],
                        nodeKey:paramKey,
                        param: workFlow[node]['inputs'][paramKey]
                    } as Param
                    params.push(_temp)
                }

            }

        }
        return params
    }

    /**
     * 根据工作流和绘画参数，提交绘画任务
     */
    static async local_draw(workflow: any, params: Param[]): Promise<DrawResponse> {
        params.forEach(item => {
            if (item.name != 'output' && item.type && item.param) {
                const node = item.type[0].split('|')[0]
                //如果没有配置参数，直接返回，使用工作流默认参数
                if (workflow[node + ''] && workflow[node + ''].inputs[item.type[1]]) {
                    workflow[node + ''].inputs[item.type[1]] = item.param
                }
            }
        })
        const output_config = params.find(item => item.name === 'output')
        if (!output_config || !output_config.type[0] || !output_config.type[0].split('|')[0]) {
            return {
                status: 'failed',
                message: '产出节点必须配置,请检查产出节点配置'
            } as DrawResponse
        }
        //从type参数中获取产出节点
        const _ouputnode = parseInt(output_config.type[0].split('|')[0])
        console.log("产出节点是", output_config)
        const _output = await this._local_excuteWithResult(workflow, {
            outputNode: _ouputnode,
            timeout: output_config.timeout || 60
        }).catch(err => {
            useSnackbarStore().showErrorMessage(err.message)
            return {status: 'failed', message: err} as DrawResponse
        })
        if (output_config.outputType === 'text') {
            //产出是本文，比如反推提示词
            return _output
        }
        if (this.useOss && _output.output?.length && _output.type === 'image' || _output.type === 'video' || _output.type === "audio") {
            for (let i = 0; i < _output.output?.length!; i++) {
                const _blob = await ImageUrlToBlob(_output.output![i])
                const uploadresult=await this.uploadImage(_blob)
                if(_output.output && uploadresult){
                    _output.output[i] =uploadresult
                }
            }
            return _output
        } else {
            return _output
        }

    }

    /**
     * 根据标准名称，例如negative，positive等分配绘画参数
     */
    private static _assignParam(_target: Param[], params: any): Param[] {
        console.log('绘画参数_target：', _target, params)
        _target.forEach(item => {
            //如果参数存在则使用传入的参数，参数不存在使用默认参数
            if (item.name === 'seed') {
                //如果没有传种子，则生成随机种子
                Object.assign(item, {param: params[item.name] ? params[item.name] : this.getSeed()})
            } else {
                //默认参数item.param和插入的参数至少存在一个，否则不进行任何操作
                if (params[item.name] || item.param) {
                    Object.assign(item, {param: params[item.name] ? params[item.name] : item.param})
                }
            }
        })
        return _target
    }

    /**
     * 保存绘画历史记录
     *
     */
    static async saveDrawHistory(drawHistory: DrawHistoryItem) {
        if (this.saveHistory) {
            const {user} = useAuthStore()
            Object.assign(drawHistory, {
                user_id: user?._id,
                status: 1,
                created_at: Date.now()
            })
            await Client_POST('/draw/history', drawHistory)
        }
    }

    /**
     * 提交绘画任务返回，绘画结果
     */
    private static _local_excuteWithResult(task: any, params: {
        outputNode: number
        timeout?: number
    }): Promise<DrawResponse> {
        return new Promise(async (resolve, reject) => {
            //先提交任务
            const timeoutid = setTimeout(() => {
                console.log('任务超时')
                reject({status: 1, message: '绘画超时'})
            }, (params.timeout || 60) * 1000)
            this.local_sendPrompt(task)
                .then((prompt_id) => {
                    //保存绘画历史
                    this.websocket.onmessage = async (event) => {
                        try {
                            const {type, data} = JSON.parse(event.data)
                            console.log(event)
                            //缓存产出，未变更种子，直接缓存阐述
                            if (
                                type === 'execution_cached' &&
                                data['nodes'].indexOf(params.outputNode + '') !== -1
                            ) {
                                // this.logger.debug(
                                //   `缓存节点${output_node}，缓存产出${data.nodes}`,
                                // );
                                const output = await this.local_getOutputByPrompId(
                                    prompt_id,
                                    {outputNode: params.outputNode},
                                );
                                if (output) {
                                    resolve(output);
                                }
                            }
                            //执行错误
                            if (type === 'execution_error') {
                                resolve({
                                    status: "failed",
                                    message: `错误节点：${data.node_id},错误信息:${data.exception_message}`
                                } as DrawResponse)
                            }
                            if (type === 'executed' && data['node'] == params.outputNode) {
                                //移除监听
                                // this.drawQueue.removeAllListeners('global:completed');
                                //解析文本
                                const {
                                    output: {tags},
                                } = data;
                                if (tags) {
                                    resolve(this.getOutPutFromWebsocket(tags, this.handleAddress(this.localHttpUrl), 'text'));
                                    return;
                                }
                                // 解析视频
                                const {
                                    output: {gifs},
                                } = data;
                                if (gifs) {
                                    resolve(this.getOutPutFromWebsocket(gifs, this.handleAddress(this.localHttpUrl), 'video'));
                                    return;
                                }
                                // 解析图片
                                const {
                                    output: {images},
                                } = data;
                                if (images) {
                                    resolve(
                                        this.getOutPutFromWebsocket(images, this.handleAddress(this.localHttpUrl), 'image'),
                                    );
                                    return;
                                }
                                //保存到数据库
                            }
                            //官方结束节点
                            if (type === 'executing' && !data['node']) {
                                //todo 任务结束
                                const output = await this.local_getOutputByPrompId(
                                    prompt_id,
                                    {outputNode: params.outputNode},
                                );
                                if (output) {
                                    resolve(output);
                                } else {
                                    // ws_client.close();
                                    reject({status: 'failed', message: '未查询到任务信息'} as DrawResponse);
                                }
                                return;
                            }

                        } catch (err) {
                            console.log(err)
                        }
                    }
                }).catch(() => {
                reject({
                    status: 1, message: '发送绘画任务失败，请检查服务器连接'
                })
            })
        })
    }

    /**
     * 生成指定长度的种子数据，默认15位，注意SD3不要超过10位
     * @param length
     */
    static getSeed(length?: number) {
        return useTokenUtilgenerateRandomNumber(length || 15)
    }

    /**
     * 发送提示词到服务器
     */
    static async local_sendPrompt(prompt: any): Promise<string> {
        const {user} = useAuthStore()
        const {prompt_id} = await this.POST('/prompt', {
            client_id: user?._id,
            prompt
        })
        return prompt_id
    }

    /**
     * 提交自定义工作流
     */
    static async local_drawCustomWorkFlow(workflow: any, params: Param[]) {
        await this.Initalize()
        return await this.local_draw(workflow, params)
    }

    /**
     * 更具prompt_id取回绘画结果
     * @param prompt_id
     * @param params
     */
    static async local_getOutputByPrompId(prompt_id: string, params: {
        outputNode: number
    }): Promise<DrawResponse | undefined> {
        const server = this.localHttpUrl;
        const data = await this.GET(
            `${server}/history/${prompt_id}`,
        );
        // this.logger.log('根据prompid获取output结果', data);
        //解析图片
        try {
            // const outputs = data[prompt_id]['outputs'][output_node]['images'];
            if (data[prompt_id]) {
                const {outputs} = data[prompt_id];
                console.log('outputs', outputs);
                if (outputs && params.outputNode && outputs[params.outputNode]) {
                    //解析图片
                    const images = outputs[params.outputNode]['images'] as unknown[];
                    if (images) {
                        return this.getOutPutFromWebsocket(images, server, 'image');
                    }
                    //解析视频
                    const videos = outputs[params.outputNode]['gifs'];
                    if (videos) {
                        return this.getOutPutFromWebsocket(videos, server, 'video');
                    }
                    //解析文本
                    const tags = outputs[params.outputNode]['tags'];
                    if (tags) {
                        return this.getOutPutFromWebsocket(tags, server, 'text');
                    }
                }
            }
            // return null;
        } catch (err) {
            console.log(err)
        }
    }

    static getOutPutFromWebsocket(
        outputs: any[],
        server: string,
        type: 'image' | 'video' | 'text' | 'audio',
    ): DrawResponse {
        if (outputs && outputs.length > 0 && type === 'image') {
            const output = [] as string[];
            for (const _item of outputs) {
                let imageUrl = '';
                //如果是微信消息
                const {filename, subfolder, type} = _item as any;
                if (subfolder) {
                    imageUrl = `${this.handleAddress(server)}/view?subfolder=${subfolder}&filename=${filename}&type=${type}`;
                } else {
                    imageUrl = `${this.handleAddress(server)}/view?filename=${filename}&type=${type}`;
                }
                console.log('getOutPutFromWebsocket最终生成的imageUr', imageUrl);
                output.push(imageUrl);
            }
            return {
                status: 'success',
                output: output,
                type: type,
            } as DrawResponse;
        } else if (outputs && outputs.length > 0 && type === 'video') {
            if (outputs && outputs.length > 0) {
                const output = [] as string[];
                for (const _item of outputs) {
                    let videourl = '';
                    //如果是微信消息
                    const {filename, subfolder, type} = _item;
                    if (subfolder) {
                        videourl = `${this.handleAddress(server)}/view?subfolder=${subfolder}&filename=${filename}&type=${type}`;
                    } else {
                        videourl = `${this.handleAddress(server)}/view?filename=${filename}&type=${type}`;
                    }
                    output.push(videourl);
                }
                return {
                    status: 'success',
                    output: output,
                    type
                } as DrawResponse;
            }
        } else if (outputs && outputs.length > 0 && type === 'text') {
            return {
                status: 'success',
                output: outputs,
                type
            } as DrawResponse;
        }
        return {
            status: 'failed',
            message: '未获得任何产出'
        } as DrawResponse
    }

    /**
     * 处理comfyUI的服务器地址，避免多出末尾的/导致运行错误
     */
    static handleAddress(http_url: string) {
        if (http_url.trim().endsWith('/')) {
            return http_url.trim().replace(/\/$/, '');
        } else {
            return http_url.trim();
        }
    }

    /**
     * 获取分享的工作流
     */
    static getSharedWorkFlow = async (user_id: string, workflow_name: string): Promise<WorkFlow | undefined> => {
        //根据用户id,获取所有的工作流
        const data = await Client_GET(`/workflow/getByUserId/${user_id}`) as UserWorkFlow
        //从data中获取名称为workflow_name的工作流
        const workflows = data["workflows"] as WorkFlow[]
        return workflows.find(item => item.name === workflow_name)
    }
    /**
     * 运行分享的工作流,可以使本地测试运行，也可以是发送到服务端
     */
    static runSharedWorkFlow = async (workflow: any, params: Param[], drawParams: ComfyUIProperties, options: ComfyUIOptions) => {
        await this.Initalize()
        //如果启用本地
        if (this.useLocal) {
            //获取工作流和参数
            this._assignParam(params, drawParams)
            return await this.local_draw(workflow, params)
        } else {
            //将参数赋值给工作流
            console.log('options',options)
            return await this.submitCustomeWorkflow(drawParams, options)
        }

    }

    /**
     * 提交自定义工作流和参数到服务器端绘图
     */
    static async submitCustomeWorkflow(params: ComfyUIProperties, options:ComfyUIOptions): Promise<DrawResponse> {
        await this.Initalize()
        const {user} = useAuthStore()
        return await Client_POST(`/draw/customeWorkflow`, {
            client_id: user?._id || "",
            socket_id: user.socket_id,
            params,
            options
        } as ComfyUIRequestParams) as DrawResponse
    }

    /**
     * 提交运行任意自定义工作流
     */
    // static async submitCommonTask(workflow:any){
    //     return  await Client_POST('/draw/submitTask', {
    //         prompt: workflow
    //     }) as string
    // }
    /**
     * 获取所有系统的服务器配置
     */
    /**
     * 初始状态获取服务器的GPU算力服务器列表
     */
    static getServerList = async ():Promise<ServerStatus[]> => {
        return  await Client_GET('draw/server') as ServerStatus[]
    }
    /**
     * 预分配服务器
     */
    static preAssignServer = async () => {
        this.preAssignedServer= await Client_GET('draw/preAssignServer') as ServerStatus
    }
    /**
     * 上传图片到OSS，返回图片url
     * @param file
     */
    static uploadImage = async (file: File | any): Promise<string | undefined> => {
        //判断是否启用OSS
        useSnackbarStore().showWarningMessage('正在上传，请等待图片上传完成')
        console.log('是否启动了OSS？', this.useOss, this.useCustomizeOss)
        if (this.useOss) {
            //清空预分配的服务器
            this.preAssignedServer=null
            return await useUtilsUploadFileToOSS(file, 'image') || ""
            // return await useFileuploadFileToQiniuOSS(file, 'image') || ""
        } else {
            console.log(file)
            return await this.uploadToComfyUIServer(file)
        }
    };

    /**
     * 将文件上传到ComfyUI服务器,返回示例{
     *     "name": "00001.png",
     *     "subfolder": "",
     *     "type": "input"
     * }
     * @param file
     */
    static async uploadToComfyUIServer(file: File): Promise<string |undefined> {
        const formdata = new FormData();
        formdata.append("image", file);
        if(this.useLocal){
            const {name} = await $fetch(`${this.localHttpUrl}/upload/image`, {
                method: 'post',
                body: formdata,
                mode: 'cors'
            }).catch(err => {
                useSnackbarStore().showErrorMessage(err)
            }) as any
            console.log(`上传图片到ComfyUI服务器${this.localHttpUrl}成功,filename${name}`)
            return `./input/${name}`
        }else {
            await this.preAssignServer()
            if(this.preAssignedServer && this.preAssignedServer.http_url){
                const serverUrl=this.handleAddress(this.preAssignedServer.http_url)
                const {name} = await $fetch(`${serverUrl}/upload/image`, {
                    method: 'post',
                    body: formdata,
                    mode: 'cors'
                }).catch(err => {
                    useSnackbarStore().showErrorMessage(err)
                }) as any
                // response.body
                console.log(`上传图片到ComfyUI服务器${serverUrl}成功,filename${name}`)
                return `./input/${name}`
            }
        }

    }

    static removebg = async (image_path: string) => {
        return await this.POST('/draw/removebg', {
            client_id: useAuthStore().user?._id,
            socket_id: useAuthStore().user?.socket_id,
            params: {
                image_path
            },
            options: {
                source: "web",
                lifo: false
            }
        })
    }
    /**
     * 具备重绘
     * @param params
     */

    static impainting = async (params: {
        image_path: string,
        image_path_mask: string,
        ckpt_name_id?: number,
        denoise?: number,
        positive?: string,
        negative?: string
    }) => {
        // 初始化
        await this.Initalize()
        if (this.useLocal) {
            const _p = workflowParams.impainting as Param[]
            Object.assign(params, {
                image_path_origin: params.image_path,
                ckpt_name: this.ckpt_names[params.ckpt_name_id || 0],
            } as ComfyUIProperties)
            this._assignParam(_p, params)
            // todo
            // return await this.local_draw(api_impainting,_p)
        } else {
            return await this.POST('/draw/inpainting', {
                client_id: useAuthStore().user?._id,
                socket_id: useAuthStore().user?.socket_id,
                params: {
                    image_path: params.image_path,
                    image_path_mask: params.image_path_mask,
                    ckpt_name_id: params.ckpt_name_id || 0,
                    denoise: params.denoise || 0.5,
                    positive: params.positive || "",
                    negative: params.negative || ""
                },
                options: {
                    source: "web",
                    lifo: false
                }
            })
        }

    }
    /**
     * 图片高清放大加细节修复，必须参数一个，图片路径，可选参数2个，降噪和放大倍数
     * @param imagepath 必须，图片路径
     * @param multiple 可选，放大倍数
     * @param denoise 可选，降噪幅度
     * @returns 返回绘图的API
     */
    static imageUpscaleAndDetailFix = async (imagepath: string, multiple?: number, denoise?: number): Promise<string> => {

        //todo
        return ""
    }
    /**
     * 图片高清放大，默认放大4倍
     * @returns
     */
    static imageUpscale = async (image_path: string): Promise<string> => {
        return await this.POST('/draw/hdfix', {
            client_id: useAuthStore().user?._id,
            socket_id: useAuthStore().user?.socket_id,
            params: {
                image_path
            },
            options: {
                source: "web",
                lifo: false
            }
        }) as string
    }
    /**
     * 抠像
     * @param params
     */
    static segmentAnything = async (params: ComfyUIProperties): Promise<DrawResponse | undefined> => {
        //调用API之前初始化参数
        await this.Initalize()
        if (this.useLocal) {
            const _workflow = this.local_getWorkFlowByWorkFlowName('segment')
            if (_workflow && _workflow.params && _workflow.workflow) {
                const {workflow, params: _p} = _workflow
                this._assignParam(_p, params)
                // console.log(typeof _flow)
                return await this.local_draw(JSON.parse(workflow), _p)
            }
        } else {
            return await this.POST('/draw/segmentAnything', {
                client_id: useAuthStore().user?._id,
                socket_id: useAuthStore().user?.socket_id,
                params,
            }) as DrawResponse
        }

    }

    /**
     * local_getWorkFlowByWorkFlowName
     * 根据API名称获取对应的工作流和参数
     */
    static local_getWorkFlowByWorkFlowName(workflow_name: string): WorkFlow | null {
        //从状态中读取
        const {workflows} = useStableDiffusionStore()
        // let _p = workflows.find(param=>param.name===apiName) as Param[]
        // // 默认工作流
        // let _flow = defaultData?.defaulWorkFlow
        // const {workflows} = useStableDiffusionStore()
        return workflows.find(item => item.name === workflow_name) || null
        // if (_tempFlow) {
        //     const _flow = _tempFlow.workflow
        //     const _p = _tempFlow.params as Param[]
        //     console.log('使用自定义工作流数据绘画', _flow, _p)
        //     return {
        //
        //         workflow: _flow,
        //         params: _p
        //     } as WorkFlow
        // }

    }

    /**
     * 普通文生图
     * @returns
     */
    static text2img = async (params: ComfyUIProperties, options?: ComfyUIOptions): Promise<DrawResponse | undefined> => {
        await this.Initalize()
        // 使用SD3绘图
        if (options?.apisource === 'sd3') {
            const sd3_result = await this.text2imgSD3({
                prompt: params.positive || "",
                aspect_ratio: params.sd3_aspect_ratio,
                negative_prompt: params.negative,
                seed: params.seed || this.getSeed(9)
            })
            return {status: 'failed', output: [sd3_result]} as DrawResponse
        }
        // 使用本地ComfyUI绘图，不经过服务器
        if (this.useLocal) {
            //从服务器获取工作流
            const _workflow = await this.workFlow_GetDefault('text2img') || this.local_getWorkFlowByWorkFlowName(options?.workflow_name || 'text2img')
            if (_workflow && _workflow.params && _workflow.workflow) {
                const {workflow, params: _p} = _workflow
                this._assignParam(_p, params)
                // console.log(typeof _flow)
                const output = await this.local_draw(JSON.parse(workflow), _p)
                // await this.saveDrawHistory({params, options, output:output.output} as DrawHistoryItem)
                if (output) {
                    return output
                }
            }
        } else {
            //调用后台服务
            options ? "" : options = {}
            options.workflow_name = "text2img"
            const res = await this.POST('/draw/text2img', {
                client_id: useAuthStore().user?._id,
                socket_id: useAuthStore().user?.socket_id,
                params,
                options,
            }) as DrawResponse
            //更新用户积分信息
            if (res.status === 'success') {
                await useAuthupdateUserInfo()
            }
            return res
        }
    }

    /**
     *图生图
     * @param params
     * @param options
     */
    static img2img = async (params: ComfyUIProperties, options?: ComfyUIOptions): Promise<DrawResponse | undefined> => {
        // 初始化
        await this.Initalize()
        if (this.useLocal) {
            const _workflow = await this.workFlow_GetDefault('img2img') || this.local_getWorkFlowByWorkFlowName(options?.workflow_name || 'img2img')
            if (_workflow && _workflow.params && _workflow.workflow) {
                const {workflow, params: _p} = _workflow
                this._assignParam(_p, params)
                console.log('绘图参数', _p)
                return await this.local_draw(JSON.parse(workflow), _p)
            }
        } else {
            options ? "" : options = {}
            options.workflow_name = "img2img"
            const _output = await this.POST('/draw/img2img', {
                client_id: useAuthStore().user?._id,
                socket_id: useAuthStore().user?.socket_id,
                params,
                options,
            }) as DrawResponse
            //更新用户积分信息
            if (_output.status === 'success') {
                await useAuthupdateUserInfo()
            }
            return _output
        }

    };
    /**
     * 图片生成视频
     */
    static image2video = async (params: ComfyUIProperties, options?: ComfyUIOptions): Promise<DrawResponse | undefined> => {
        await this.Initalize()
        if (this.useLocal) {
            const _workflow = await this.workFlow_GetDefault('img2video') || this.local_getWorkFlowByWorkFlowName(options?.workflow_name || 'img2video')
            if (_workflow && _workflow.params && _workflow.workflow) {
                const {workflow, params: _p} = _workflow
                this._assignParam(_p, params)
                console.log('绘图参数', _p)
                return await this.local_draw(JSON.parse(workflow), _p)
            }
        } else {
            options ? "" : options = {}
            options.workflow_name = "img2video"
            const _output = await this.POST('/draw/img2video', {
                client_id: useAuthStore().user?._id,
                socket_id: useAuthStore().user?.socket_id,
                params,
                options,
            }) as DrawResponse
            //更新用户积分信息
            if (_output.status === 'success') {
                await useAuthupdateUserInfo()
            }
            return _output
        }

    }

    /**
     *
     * @param params
     * @param options
     */
    static aimodel = async (params: ComfyUIProperties, options?: ComfyUIOptions): Promise<DrawResponse | undefined> => {
        await this.Initalize()
        if (this.useLocal) {
            const _workflow = this.local_getWorkFlowByWorkFlowName(options?.workflow_name || 'aimodel')
            if (_workflow && _workflow.params && _workflow.workflow) {
                const {workflow, params: _p} = _workflow
                this._assignParam(_p, params)
                console.log('绘图参数', _p)
                return await this.local_draw(JSON.parse(workflow), _p)
            }
        } else {
            return await this.POST('/draw/model', {
                client_id: useAuthStore().user?._id,
                socket_id: useAuthStore().user?.socket_id,
                params,
                options,
            }) as DrawResponse
        }

    }
    /**
     * AI写真
     * @param params
     * @param options
     * @constructor
     */
    static faceswap = async (params: ComfyUIProperties, options?: ComfyUIOptions): Promise<DrawResponse | undefined> => {
        // 初始化
        await this.Initalize()
        if (this.useLocal) {
            const _workflow = this.local_getWorkFlowByWorkFlowName(options?.workflow_name || 'faceSwap')
            if (_workflow && _workflow.params && _workflow.workflow) {
                const {workflow, params: _p} = _workflow
                this._assignParam(_p, params)
                console.log('绘图参数', _p)
                return await this.local_draw(JSON.parse(workflow), _p)
            }
        } else {
            //调用服务器端
            return await this.POST('/draw/faceswap', {
                client_id: useAuthStore().user?._id,
                socket_id: useAuthStore().user?.socket_id,
                params,
                options,
            }) as DrawResponse
        }

    }
    /**
     * 图片反推提示词
     */
    static image2tagger = async (params: ComfyUIProperties, options?: ComfyUIOptions): Promise<DrawResponse | undefined> => {
        //调用API之前初始化参数
        await this.Initalize()
        if (this.useLocal) {
            const _workflow = this.local_getWorkFlowByWorkFlowName(options?.workflow_name || 'img2tagger')
            if (_workflow && _workflow.params && _workflow.workflow) {
                const {workflow, params: _p} = _workflow
                this._assignParam(_p, params)
                console.log('绘图参数', _p)
                return await this.local_draw(JSON.parse(workflow), _p)
            }
        } else {
            return await this.POST('/draw/image2tagger', {
                client_id: useAuthStore().user?._id,
                socket_id: useAuthStore().user?.socket_id,
                params,
                options,
            }) as DrawResponse
        }
    }
    /**
     * 验证图片的文件大小和宽高不超过1024，文件大小不超过4M
     * @param file
     * @returns
     */
    static validateImage = async (file: any): Promise<boolean> => {
        return new Promise((resolve, reject) => {
            console.log(file.size)
            if (!file.size || file.size > 4048000) {
                resolve(false)
            }
            const _URL = window.URL || window.webkitURL;
            const image = new Image();
            image.src = _URL.createObjectURL(file)
            console.log(_URL.createObjectURL(file))
            image.onload = function () {
                // console.log(image.width>1024||image.height>1024)
                if (image.width > 1200 || image.height > 1200) {
                    resolve(false)
                } else {
                    resolve(true)
                }
            }
        })
    }
    /**
     * 封装post请求，请求本地或者本地的ComfyUI服务器
     * @param url
     * @param body
     * @constructor
     */
    static POST = async (url: string, body: any): Promise<any> => {
        // console.log("@SSR POST发送的数据",body)
        const data = await $fetch(url, {
            method: 'post',
            baseURL: this.useLocal ? this.localHttpUrl.trim().replace(/\/$/, '') : useRuntimeConfig().public.baseApiurl,
            mode: 'cors',
            body: body
        }).catch(err => {
            console.log(err)
            useSnackbarStore().showErrorMessage(`连接绘画服务器${this.useLocal ? this.localHttpUrl.trim().replace(/\/$/, '') : useRuntimeConfig().public.baseApiurl}，发生错误！${err.message}`)
            //将绘画状态调整为false
            useStableDiffusionStore().isGernateDisable = false
        });
        console.log("@ComfyUI_POST 获取的data数据", data)
        return data
    }
    /**
     * fetch get请求,请求本地或者本地的ComfyUI服务器
     * @param url
     * @constructor
     */
    public static GET = async (url: string): Promise<any> => {
        // console.log("@SSR POST发送的数据",body)
        const data = await $fetch(url, {
            method: 'get',
            mode: 'cors',
            // baseURL: '/api',
            baseURL: this.useLocal ? this.localHttpUrl.trim().replace(/\/$/, '') : useRuntimeConfig().public.baseApiurl,
        }).catch(err => {
            useSnackbarStore().showErrorMessage(`连接绘画服务器${this.useLocal ? this.localHttpUrl.trim().replace(/\/$/, '') : useRuntimeConfig().public.baseApiurl}，发生错误！`)
            useStableDiffusionStore().isGernateDisable = false
        });
        console.log("@ComfyUI_GET 获取的data数据", data)
        return data
    }


    static async text2imgSD3(params: {
        prompt: string;
        mode?: 'text-to-image' | 'image-to-image';
        aspect_ratio?: SD3AspectRatio;
        negative_prompt?: string;
        model?: 'sd3' | 'sd3-turbo';
        image?: any; //image-to-image 必须
        strength?: number; //image-to-image 必须
        seed?: number;
        style_preset?: SD3StylePreset;
    }) {
        const sd3url = 'https://api.stability.ai/v2beta/stable-image/generate/sd3';
        // const formData = new FormData();
        // formData.append('prompt', params.prompt);
        // formData.append('mode', params.mode || 'text-to-image');
        // formData.append('negative_prompt', params.negative_prompt || '');
        // formData.append('model', params.model || 'sd3');
        // formData.append('image', params.image);
        // formData.append('strength', params.strength || 0.5);
        // formData.append('seed', this.getSeed(9));
        // formData.append('style_preset', params.style_preset || '');
        // formData.append('output_format', 'png');
        // if (params.mode === 'text-to-image') {
        //   formData.append('aspect_ratio', params.aspect_ratio || '1:1');
        // }
        const formData = {
            prompt: params.prompt,
            mode: params.mode || 'text-to-image',
            negative_prompt: params.negative_prompt || '',
            model: params.model || 'sd3',
            seed: this.getSeed(9),
            style_preset: params.style_preset || '',
            output_format: 'png',
        };
        if (!params.mode || params.mode === 'text-to-image') {
            Object.assign(formData, {
                aspect_ratio: params.aspect_ratio || '1:1',
            });
        }
        if (params.mode === 'image-to-image') {
            Object.assign(formData, {
                strength: params.strength || 0.5,
                image: params.image,
            });
        }
        console.log('提交SD的绘画数据', formData);
        const response = await this.comfyuiAxios.postForm(
            sd3url,
            axios.toFormData(formData, new FormData()),
            {
                validateStatus: undefined,
                responseType: 'arraybuffer',
                headers: {
                    Authorization: `Bearer ${this.sd3_key}`,
                    Accept: 'image/*',
                    ContentType: 'multipart/form-data',
                },
            },
        );
        //将获取的Buffer转换为图片文件
        if (response.status === 200) {
            // console.log('data', response.data);
            const buffer = Buffer.from(response.data);
            //将Buffer上传到阿里云
            return await this.uploadImage(buffer);
        } else {
            console.log(response.request);
            throw new Error(`${response.status}: ${response.data.toString()}`);
        }
    }

    private static comfyuiAxios = axios.create({
        // baseURL: "/sdApi",
        timeout: 1000000,
        //允许跨域
        headers: {
            'Access-Control-Allow-Origin': '*',
            Accept: '*/*',
        },
    });

}


export interface DrawTask {
    client_id: string,
    socket_id: string,
    params: Object,
    options: {
        source: "web" | "wechat",
        lifo: boolean
    }
}

export type SD3AspectRatio =
    | '1:1'
    | '16:9'
    | '21:9'
    | '2:3'
    | '3:2'
    | '3:4'
    | '4:3'
    | '9:16';
type SD3StylePreset =
    | '3d-model'
    | 'analog-film'
    | 'anime'
    | 'cinematic'
    | 'comic-book'
    | 'digital-art'
    | 'enhance'
    | 'fantasy-art'
    | 'isometric'
    | 'line-art'
    | 'low-poly'
    | 'modeling-compound'
    | 'neon-punk'
    | 'origami'
    | 'photographic'
    | 'pixel-art'
    | 'tile-texture';

export interface DrawResponse {
    status: 'submitted' | 'success' | 'failed';
    output?: string[]; //数组，图像url,如果使用批次则是多张图，不适用批次为单张图
    type?: 'text' | 'image' | 'video' | 'audio'; //输出文件类型
    message?: string;  //错误消息
}

export interface UserWorkFlow {
    user_id: string
    workflows: WorkFlow[]
}

export interface WorkFlow {
    title?: string //显示名称
    name?: string  //标准名称，需要保持唯一
    params?: Param[] //参数
    workflow?: string  //工作流
    cover?: string  //封面图
    preview?: string  //预览图
    is_public?: boolean //是否公开
    description?: string //工作流描述
    power?: number //   算力消耗
    nodeCount?: number //节点数
    runTime?: number  //运行时间，秒
    sortNumber?: number //排序
}

export interface ComfyUIOptions {
    source?: 'web' | 'wechat';  //默认web,web端调用不需要传值
    apisource?: 'sd3' | 'default';    //,默认default,使用sd3官方API绘图时传sd3
    lifo?: boolean;    //优先
    servername?:string; //服务器名称
    workflow_user_id?: string; //工作流作者id，不传默认使用admin
    workflow_name?: string; //工作流名称,使用自定义工作流必须
}


export interface ComfyUIRequestParams {
    params: ComfyUIProperties;
    client_id?: string;
    socket_id?: string;
    options?: ComfyUIOptions;
}

export interface DrawHistoryItem {
    _id?: string
    user_id?: string
    prompt_id?: string
    params?: ComfyUIProperties,
    created_at?: number
    options?: ComfyUIOptions
    status?: 0 | 1
    output?: string[]
    type?: 'image' | 'text' | 'video'
}

//产出接口
export interface OutPut {
    result: string,
    type: OutputType,
    params: ComfyUIProperties
}

//服务器状态
export interface ServerStatus {
    _id: string,
    name: string,
    http_url: string,
    queue: number,
    enabled: boolean, //是否启用
    status: 0 | 1,  //0:offline, 1:online
}

//产出类型
export type OutputType = 'image' | 'video' | 'text' | 'audio'
